package demo4;

//克隆就是把一个对象复制一份，放进一个新地址。
//Object类中的clone方法，是浅拷贝，即复制对象的引用，而不是复制对象。
//Object里的clone是protected方法，所以在不同包下要通过super访问，而在main里不能用super，
// 我们希望通过实例化对象调用这个方法，这样才能克隆当前这个对象，所以要在子类重写clone方法。

class Money {
    int money;
    public Money(int money) {
        this.money = money;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
        //调用父类的clone来克隆当前的对象
    }
}

class Person implements Cloneable{
    String name;
    int age;
    Money m;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        this.m = new Money(100);  //在构造方法里实例化
    }
    @Override
    protected Person clone() throws CloneNotSupportedException {
        //深拷贝
//        Person tmp = (Person)super.clone();
//        tmp.m = (Money)this.m.clone(); //person1调用那this就是person1，所以person1的m也被克隆放到tmp里
//        return tmp;

        //浅拷贝
        return (Person)super.clone();
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class cloneable_test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("张三", 18);
        Person person2 = (Person) person1.clone();

        //这里会出现第一个报错：clone 这是因为throws...表示编译时异常，不能编译通过所以在main后✌加上
        //处理完，整条语句都报错，因为clone()的返回值是Person类型，所以要强转一下。
        //再运行仍然会报错：不支持克隆。如果自定义类型想要实现克隆，就要实现一个和接口：Cloneable接口。
        // Cloneable接口是一个空接口，或标记接口，没有方法，只是用来标识一个类是支持克隆的。所以加上这个就能运行了。
        // Cloneable接口是java.lang包下的，所以不用导包。
        System.out.println(person1);
        System.out.println(person2);
        System.out.println("=========================");
        person2.name = "李四";
        System.out.println(person1.name);
        System.out.println(person2.name);
        System.out.println("=========================");
        person2.m.money = 200;
        System.out.println(person1.m.money);
        System.out.println(person2.m.money);  //这里发现都改了
        //Cloneable是浅拷贝，并没有将对象中的对象克隆。
        //对象中的m是一个引用，里面存着money的引用，浅拷贝只是拷贝了m的引用，里面的money并没有分配新引用，是同一个

    }
}
